home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / amiga / convrtrs / pbmplus / update5.lha / src / ppm / ppmtoilbm.c < prev   
Encoding:
C/C++ Source or Header  |  1993-09-01  |  30.6 KB  |  996 lines

  1. /* ppmtoilbm.c - read a portable pixmap and produce an IFF ILBM file
  2. **
  3. ** Copyright (C) 1989 by Jef Poskanzer.
  4. ** Modified 20/Jun/93 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
  5. **  - 24bit support (new options -24if, -24force)
  6. **  - HAM8 support (well, anything from HAM3 to HAM(MAXPLANES))
  7. **  - now writes up to 8 (16) planes (new options -maxplanes, -fixplanes)
  8. **  - colormap file (new option -map)
  9. **  - write colormap only (new option -cmaponly)
  10. **  - only writes CAMG chunk if its a HAM-picture
  11. ** Modified 29/Aug/93 by Ingo Wilken
  12. **  - operates row-by-row whenever possible
  13. **  - faster colorscaling with lookup-table (~20% faster on HAM pictures)
  14. **  - options -ham8 and -ham6 now imply -hamforce
  15. **
  16. **
  17. **           std   HAM  24bit cmap  direct
  18. **  -------+-----+-----+-----+-----+-----
  19. **  BMHD     yes   yes   yes   yes   yes
  20. **  CMAP     yes   (1)   no    yes   no
  21. **  BODY     yes   yes   yes   no    yes
  22. **  other    -     CAMG  -     -     DCOL
  23. **  nPlanes  1-8   3-8   24    0     3-24   if configured without ILBM_BIGRAW
  24. **  nPlanes  1-16  3-16  24    0     3-48   if configured with ILBM_BIGRAW
  25. **
  26. **  (1): grayscale colormap
  27. **
  28. ** Permission to use, copy, modify, and distribute this software and its
  29. ** documentation for any purpose and without fee is hereby granted, provided
  30. ** that the above copyright notice appear in all copies and that both that
  31. ** copyright notice and this permission notice appear in supporting
  32. ** documentation.  This software is provided "as is" without express or
  33. ** implied warranty.
  34. */
  35.  
  36. #include "ppm.h"
  37. #include "ppmcmap.h"
  38. #include "ilbm.h"
  39.  
  40.  
  41. #define MODE_DIRECT     4   /* direct color ILBM */
  42. #define MODE_CMAP       3   /* write normal file, but colormap only */
  43. #define MODE_24         2   /* write a 24bit (deep) ILBM */
  44. #define MODE_HAM        1   /* write a HAM */
  45. #define MODE_NONE       0   /* write a normal picture */
  46.  
  47. #define ECS_MAXPLANES   5
  48. #define ECS_HAMPLANES   6
  49. #define AGA_MAXPLANES   8
  50. #define AGA_HAMPLANES   8
  51.  
  52. #ifdef AMIGA_AGA
  53. #define DEF_MAXPLANES   AGA_MAXPLANES
  54. #define DEF_HAMPLANES   AGA_HAMPLANES
  55. #else
  56. #define DEF_MAXPLANES   ECS_MAXPLANES
  57. #define DEF_HAMPLANES   ECS_HAMPLANES
  58. #endif
  59. #define DEF_DCOLPLANES  5
  60.  
  61.  
  62. static int colorstobpp ARGS((int colors));
  63. #define put_fourchars(str)  (void)(fputs(str, stdout))
  64. static void put_big_short ARGS((short s));
  65. static void put_big_long ARGS((long l));
  66. #define put_byte(b)     (void)(putc((unsigned char)(b), stdout))
  67. static void ppm_to_ham ARGS((FILE *fp, int cols, int rows, int maxval, int hambits));
  68. static void ppm_to_24  ARGS((FILE *fp, int cols, int rows, int maxval));
  69. static void ppm_to_direct  ARGS((FILE *fp, int cols, int rows, int maxval, DirectColor *direct));
  70. static void ppm_to_std ARGS((FILE *fp, int cols, int rows, int maxval, colorhist_vector chv, int colors, int nPlanes));
  71. static void ppm_to_cmap ARGS((int maxval, colorhist_vector chv, int colors));
  72. static void write_form_ilbm ARGS((int size));
  73. static void write_bmhd ARGS((int cols, int rows, int nPlanes));
  74. static void write_std_cmap ARGS((colorhist_vector chv, int colors, int maxval));
  75. static void encode_row ARGS((rawtype *row, int cols, int nPlanes));
  76. static int get_int_val ARGS((char *string, char *option, int bot, int top));
  77. static pixel * next_pixrow ARGS((FILE *fp, int row));
  78. static pixval * make_val_table ARGS((pixval oldmaxval, pixval newmaxval));
  79. static void * xmalloc ARGS((int bytes));
  80. static void init_read ARGS((FILE *fp, int *colsP, int *rowsP, pixval *maxvalP, int readall));
  81.  
  82.  
  83. static unsigned char *coded_rowbuf;
  84. static pixel **pixels;
  85. static pixel *pixrow;
  86.  
  87. #define NEWDEPTH(pix, table)   PPM_ASSIGN((pix), (table)[PPM_GETR(pix)], (table)[PPM_GETG(pix)], (table)[PPM_GETB(pix)])
  88.  
  89. #define MAXCOLORS       (1<<maxplanes)
  90.  
  91. int
  92. main(argc, argv)
  93.     int argc;
  94.     char *argv[];
  95. {
  96.     FILE *ifp;
  97.     int argn, rows, cols, colors, nPlanes;
  98.     int ifmode, forcemode, maxplanes, fixplanes, hambits, mode;
  99.     pixval maxval;
  100.     colorhist_vector chv;
  101.     DirectColor dcol;
  102.     char *mapfile;
  103.     char *usage =
  104. "[-ecs|-aga] [-ham6|-ham8] [-maxplanes|-mp n] [-fixplanes|-fp n] \
  105. [-normal|-hamif|-hamforce|-24if|-24force|-dcif|-dcforce|-cmaponly] \
  106. [-hambits|-hamplanes n] [-dcbits|-dcplanes r g b] \
  107. [-map ppmfile] [ppmfile]";
  108.  
  109.     ppm_init(&argc, argv);
  110.  
  111.     ifmode = MODE_NONE; forcemode = MODE_NONE;
  112.     maxplanes = DEF_MAXPLANES; fixplanes = 0;
  113.     hambits = DEF_HAMPLANES;
  114.     mapfile = NULL;
  115.     dcol.r = dcol.g = dcol.b = DEF_DCOLPLANES;
  116.  
  117.     argn = 1;
  118.     while( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
  119.         if( pm_keymatch(argv[argn], "-maxplanes", 4) || pm_keymatch(argv[argn], "-mp", 3) ) {
  120.             if( ++argn >= argc )
  121.                 pm_usage(usage);
  122.             maxplanes = get_int_val(argv[argn], argv[argn-1], 1, MAXPLANES);
  123.             fixplanes = 0;
  124.         }
  125.         else
  126.         if( pm_keymatch(argv[argn], "-fixplanes", 4) || pm_keymatch(argv[argn], "-fp", 3) ) {
  127.             if( ++argn >= argc )
  128.                 pm_usage(usage);
  129.             fixplanes = get_int_val(argv[argn], argv[argn-1], 1, MAXPLANES);
  130.             maxplanes = fixplanes;
  131.         }
  132.         else
  133.         if( pm_keymatch(argv[argn], "-map", 4) ) {
  134.             if( ++argn >= argc )
  135.                 pm_usage(usage);
  136.             mapfile = argv[argn];
  137.         }
  138.         else
  139.         if( pm_keymatch(argv[argn], "-cmaponly", 3) ) {
  140.             forcemode = MODE_CMAP;
  141.         }
  142.         else
  143.         if( pm_keymatch(argv[argn], "-hambits", 5) || pm_keymatch(argv[argn], "-hamplanes", 5) ) {
  144.             if( ++argn > argc )
  145.                 pm_usage(usage);
  146.             hambits = get_int_val(argv[argn], argv[argn-1], 3, MAXPLANES);
  147.         }
  148.         else
  149.         if( pm_keymatch(argv[argn], "-ham6", 5) ) {
  150.             hambits = ECS_HAMPLANES;
  151.             forcemode = MODE_HAM;
  152.         }
  153.         else
  154.         if( pm_keymatch(argv[argn], "-ham8", 5) ) {
  155.             hambits = AGA_HAMPLANES;
  156.             forcemode = MODE_HAM;
  157.         }
  158.         else
  159.         if( pm_keymatch(argv[argn], "-ecs", 2) ) {
  160.             maxplanes = ECS_MAXPLANES;
  161.             hambits = ECS_HAMPLANES;
  162.         }
  163.         else
  164.         if( pm_keymatch(argv[argn], "-aga", 2) ) {
  165.             maxplanes = AGA_MAXPLANES;
  166.             hambits = AGA_HAMPLANES;
  167.         }
  168.         else
  169.         if( pm_keymatch(argv[argn], "-hamif", 5) )
  170.             ifmode = MODE_HAM;
  171.         else
  172.         if( pm_keymatch(argv[argn], "-nohamif", 7) ) {
  173.             if( ifmode == MODE_HAM )
  174.                 ifmode = MODE_NONE;
  175.         }
  176.         else
  177.         if( pm_keymatch(argv[argn], "-hamforce", 5) )
  178.             forcemode = MODE_HAM;
  179.         else
  180.         if( pm_keymatch(argv[argn], "-nohamforce", 7) ) {
  181.             if( forcemode == MODE_HAM )
  182.                 forcemode = MODE_NONE;
  183.         }
  184.         else
  185.         if( pm_keymatch(argv[argn], "-24if", 4) )
  186.             ifmode = MODE_24;
  187.         else
  188.         if( pm_keymatch(argv[argn], "-no24if", 6) ) {
  189.             if( ifmode == MODE_24 )
  190.                 ifmode = MODE_NONE;
  191.         }
  192.         else
  193.         if( pm_keymatch(argv[argn], "-24force", 4) )
  194.             forcemode = MODE_24;
  195.         else
  196.         if( pm_keymatch(argv[argn], "-no24force", 6) ) {
  197.             if( forcemode == MODE_24 )
  198.                 forcemode = MODE_NONE;
  199.         }
  200.         else
  201.         if( pm_keymatch(argv[argn], "-dcif", 4) ) {
  202.             ifmode = MODE_DIRECT;
  203.         }
  204.         else
  205.         if( pm_keymatch(argv[argn], "-nodcif", 6) ) {
  206.             if( ifmode == MODE_DIRECT )
  207.                 ifmode = MODE_NONE;
  208.         }
  209.         else
  210.         if( pm_keymatch(argv[argn], "-dcforce", 4) ) {
  211.             forcemode = MODE_DIRECT;
  212.         }
  213.         else
  214.         if( pm_keymatch(argv[argn], "-nodcforce", 6) ) {
  215.             if( forcemode == MODE_DIRECT )
  216.                 forcemode = MODE_NONE;
  217.         }
  218.         else
  219.         if( pm_keymatch(argv[argn], "-dcbits", 4) || pm_keymatch(argv[argn], "-dcplanes", 4) ) {
  220.             char *option = argv[argn];
  221.  
  222.             if( ++argn >= argc )
  223.                 pm_usage(usage);
  224.             dcol.r = (unsigned char) get_int_val(argv[argn], option, 1, MAXPLANES);
  225.             if( ++argn >= argc )
  226.                 pm_usage(usage);
  227.             dcol.g = (unsigned char) get_int_val(argv[argn], option, 1, MAXPLANES);
  228.             if( ++argn >= argc )
  229.                 pm_usage(usage);
  230.             dcol.b = (unsigned char) get_int_val(argv[argn], option, 1, MAXPLANES);
  231.         }
  232.         else
  233.         if( pm_keymatch(argv[argn], "-normal", 4) )
  234.             ifmode = forcemode = MODE_NONE;
  235.         else
  236.             pm_usage(usage);
  237.         ++argn;
  238.     }
  239.  
  240.     if( argn < argc ) {
  241.         ifp = pm_openr(argv[argn]);
  242.         ++argn;
  243.     }
  244.     else
  245.         ifp = stdin;
  246.  
  247.     if( argn != argc )
  248.         pm_usage( usage );
  249.  
  250.     if( forcemode != MODE_NONE && mapfile != NULL )
  251.         pm_message("warning - mapfile only used for normal ILBMs");
  252.  
  253.     mode = forcemode;
  254.     switch( forcemode ) {
  255.         case MODE_HAM:
  256.             /* grayscale colormap for now - we don't need to read the whole
  257.                file into memory and can use row-by-row operation */
  258.             init_read(ifp, &cols, &rows, &maxval, 0);
  259.             pm_message("hamforce option used - proceeding to write a HAM%d file", hambits);
  260.             break;
  261.         case MODE_24:
  262.             init_read(ifp, &cols, &rows, &maxval, 0);
  263.             pm_message("24force option used - proceeding to write a 24bit file");
  264.             break;
  265.         case MODE_DIRECT:
  266.             init_read(ifp, &cols, &rows, &maxval, 0);
  267.             pm_message("dcforce option used - proceeding to write a %d:%d:%d direct color file",
  268.                         dcol.r, dcol.g, dcol.b);
  269.             break;
  270.         case MODE_CMAP:
  271.             /* must read the whole file into memory */
  272.             init_read(ifp, &cols, &rows, &maxval, 1);
  273.  
  274.             /* Figure out the colormap. */
  275.             pm_message("computing colormap...");
  276.             chv = ppm_computecolorhist(pixels, cols, rows, MAXCMAPCOLORS, &colors);
  277.             if( chv == (colorhist_vector)NULL )
  278.                 pm_error("too many colors - try doing a 'ppmquant %d'", MAXCMAPCOLORS);
  279.             pm_message("%d colors found", colors);
  280.             break;
  281.         default:
  282.             /* must read the whole file into memory */
  283.             init_read(ifp, &cols, &rows, &maxval, 1);
  284.  
  285.             /* Figure out the colormap. */
  286.             if( mapfile ) {
  287.                 int mapcols, maprows, row, col;
  288.                 pixel **mappixels, *pP;
  289.                 pixval mapmaxval;
  290.  
  291.                 pm_message("reading colormap file...");
  292.                 ifp = pm_openr(mapfile);
  293.                 mappixels = ppm_readppm(ifp, &mapcols, &maprows, &mapmaxval);
  294.                 pm_close(ifp);
  295.                 if( mapcols == 0 || maprows == 0 )
  296.                     pm_error("null colormap??");
  297.  
  298.                 /* if the maxvals of the ppmfile and the mapfile are the same,
  299.                  * then the scaling to MAXCOLVAL (if necessary) will be done by
  300.                  * the write_std_cmap() function.
  301.                  * Otherwise scale them both to MAXCOLVAL.
  302.                  */
  303.                 if( maxval != mapmaxval ) {
  304.                     if( mapmaxval != MAXCOLVAL ) {
  305.                         pixval *table;
  306.                         pm_message("colormap maxval is not %d - rescaling colormap...", MAXCOLVAL);
  307.                         table = make_val_table(mapmaxval, MAXCOLVAL);
  308.                         for( row = 0; row < maprows; ++row )
  309.                             for( col = 0, pP = mappixels[row]; col < mapcols; ++col, ++pP )
  310.                                 NEWDEPTH(*pP, table);   /* was PPM_DEPTH( *pP, *pP, mapmaxval, MAXCOLVAL ); */
  311.                         mapmaxval = MAXCOLVAL;
  312.                         free(table);
  313.                     }
  314.  
  315.                     if( maxval != mapmaxval ) {
  316.                         pixval *table;
  317.                         pm_message("rescaling colors of picture...");
  318.                         table = make_val_table(maxval, mapmaxval);
  319.                         for( row = 0; row < rows; ++row )
  320.                             for( col = 0, pP = pixels[row]; col < cols; ++col, ++pP )
  321.                                 NEWDEPTH(*pP, table);   /* was PPM_DEPTH( *pP, *pP, maxval, mapmaxval ); */
  322.                         maxval = mapmaxval;
  323.                         free(table);
  324.                     }
  325.                 }
  326.  
  327.                 pm_message("computing colormap...");
  328.                 chv = ppm_computecolorhist(mappixels, mapcols, maprows, MAXCMAPCOLORS, &colors);
  329.                 ppm_freearray(mappixels, maprows);
  330.                 if( chv == (colorhist_vector)NULL )
  331.                     pm_error("too many colors in colormap!");
  332.                 pm_message("%d colors found in colormap", colors);
  333.  
  334.                 nPlanes = fixplanes = maxplanes = colorstobpp(colors);
  335.             }
  336.             else {
  337.                 pm_message("computing colormap...");
  338.                 chv = ppm_computecolorhist( pixels, cols, rows, MAXCOLORS, &colors);
  339.                 if( chv == (colorhist_vector)0 ) {
  340.                     /* too many colors */
  341.                     mode = ifmode;
  342.                     switch( ifmode ) {
  343.                         case MODE_HAM:
  344.                             pm_message("too many colors - proceeding to write a HAM%d file", hambits);
  345.                             pm_message("if you want a non-HAM file, try doing a 'ppmquant %d'", MAXCOLORS);
  346.                             break;
  347.                         case MODE_24:
  348.                             pm_message("too many colors - proceeding to write a 24bit file" );
  349.                             pm_message("if you want a non-24bit file, try doing a 'ppmquant %d'", MAXCOLORS);
  350.                             break;
  351.                         case MODE_DIRECT:
  352.                             pm_message("too many colors - proceeding to write a %d:%d:%d direct color file",
  353.                                         dcol.r, dcol.g, dcol.b);
  354.                             pm_message("if you want a non-direct-color file, try doing a 'ppmquant %d'", MAXCOLORS);
  355.                             break;
  356.                         default:
  357.                             pm_message( "too many colors for %d planes", maxplanes );
  358.                             pm_message( "either use -hamif/-hamforce/-24if/-24force/-dcif/-dcforce/-maxplanes,");
  359.                             pm_error( "or try doing a 'ppmquant %d'", MAXCOLORS );
  360.                             break;
  361.                     }
  362.                 }
  363.                 else {
  364.                     pm_message("%d colors found", colors);
  365.                     nPlanes = colorstobpp(colors);
  366.                     if( fixplanes > nPlanes )
  367.                         nPlanes = fixplanes;
  368.                 }
  369.             }
  370.             break;
  371.     }
  372.  
  373.     if( mode != MODE_CMAP )
  374.         coded_rowbuf= (unsigned char *)xmalloc(RowBytes(cols));
  375.  
  376.     switch( mode ) {
  377.         case MODE_HAM:
  378.             ppm_to_ham(ifp, cols, rows, maxval, hambits);
  379.             break;
  380.         case MODE_24:
  381.             ppm_to_24(ifp, cols, rows, maxval);
  382.             break;
  383.         case MODE_DIRECT:
  384.             ppm_to_direct(ifp, cols, rows, maxval, &dcol);
  385.             break;
  386.         case MODE_CMAP:
  387.             ppm_to_cmap(maxval, chv, colors);
  388.             break;
  389.         default:
  390.             ppm_to_std(ifp, cols, rows, maxval, chv, colors, nPlanes);
  391.             break;
  392.     }
  393.     pm_close(ifp);
  394.     exit(0);
  395. }
  396.  
  397.  
  398. static void
  399. ppm_to_ham(fp, cols, rows, maxval, hambits)
  400.     FILE *fp;
  401.     int cols, rows, maxval, hambits;
  402. {
  403.     int colors, colbits, nPlanes, formsize, cmapsize, i, hammaxval;
  404.     pixel *pP;
  405.     register int row, col;
  406.     pixval *table = NULL;
  407.     rawtype *raw_rowbuf;
  408.  
  409.     raw_rowbuf = (rawtype *)xmalloc(cols * sizeof(rawtype));
  410.     colbits = hambits-2;
  411.     colors = 1 << colbits;
  412.     hammaxval = pm_bitstomaxval(colbits);
  413.     nPlanes = hambits;
  414.     cmapsize = colors * 3;
  415.     if( odd(cmapsize) )
  416.         cmapsize++;     /* pad CMAP to a word */
  417.  
  418.     formsize =
  419.         4 +                                         /* ILBM */
  420.         4 + 4 + 20 +                                /* BMHD size header */
  421.         4 + 4 + 4 +                                 /* CAMG size val */
  422.         4 + 4 + cmapsize +                          /* CMAP size colormap */
  423.         4 + 4 + rows * nPlanes * RowBytes(cols);    /* BODY size data */
  424.  
  425.     write_form_ilbm(formsize);
  426.     write_bmhd(cols, rows, nPlanes);
  427.  
  428.     /* write camg */
  429.     put_fourchars("CAMG");
  430.     put_big_long(4);
  431.     put_big_long(vmHAM);
  432.  
  433.     /* write grayscale colormap */
  434.     put_fourchars("CMAP");
  435.     put_big_long(colors * 3);
  436.     table = make_val_table(hammaxval, MAXCOLVAL);
  437.     for( i = 0; i < colors; i++ ) {
  438.         put_byte( table[i] );   /* red */
  439.         put_byte( table[i] );   /* green */
  440.         put_byte( table[i] );   /* blue */
  441.     }
  442.     free(table); table = NULL;
  443.     if( odd(colors * 3) )
  444.         put_byte(0);
  445.  
  446.     /* write body */
  447.     put_fourchars("BODY");
  448.     put_big_long(rows * nPlanes * RowBytes(cols));
  449.  
  450.     if( hammaxval != maxval )
  451.         table = make_val_table(maxval, hammaxval);
  452.  
  453.     for( row = 0; row < rows; row++ ) {
  454.         register int noprev, pr, pg, pb, r, g, b, l;
  455.  
  456.         noprev = 1;
  457.         for( col = 0, pP = next_pixrow(fp, row); col < cols; col++, pP++ ) {
  458.             r = PPM_GETR( *pP );
  459.             g = PPM_GETG( *pP );
  460.             b = PPM_GETB( *pP );
  461.             l = (int)(PPM_LUMIN(*pP) + 0.5); /* -IUW added '+ 0.5' */
  462.             if( table ) {
  463.                 r = table[r];
  464.                 g = table[g];
  465.                 b = table[b];
  466.                 l = table[l];
  467.             }
  468.  
  469.             if( noprev ) {
  470.                 /* No previous pixels, gotta use the gray option. */
  471.                 raw_rowbuf[col] = l /* + (HAMCODE_CMAP << colbits) */;
  472.                 pr = pg = pb = l;
  473.                 noprev = 0;
  474.             }
  475.             else {
  476.                 register int dred, dgreen, dblue, dgray;
  477.                 /* Compute distances for the four options. */
  478.                 dred = abs( g - pg ) + abs( b - pb );
  479.                 dgreen = abs( r - pr ) + abs( b - pb );
  480.                 dblue = abs( r - pr ) + abs( g - pg );
  481.                 dgray = abs( r - l ) + abs( g - l ) + abs( b - l );
  482.  
  483.                 if( dgray <= dred && dgray <= dgreen && dgray <= dblue ) {      /* -IUW  '<=' was '<'  */
  484.                     raw_rowbuf[col] = l /* + (HAMCODE_CMAP << colbits) */;
  485.                     pr = pg = pb = l;
  486.                 }
  487.                 else
  488.                 if( dblue <= dred && dblue <= dgreen ) {
  489.                     raw_rowbuf[col] = b + (HAMCODE_BLUE << colbits);
  490.                     pb = b;
  491.                 }
  492.                 else
  493.                 if( dred <= dgreen ) {
  494.                     raw_rowbuf[col] = r + (HAMCODE_RED << colbits);
  495.                     pr = r;
  496.                 }
  497.                 else {
  498.                     raw_rowbuf[col] = g + (HAMCODE_GREEN << colbits);
  499.                     pg = g;
  500.                 }
  501.             }
  502.         }
  503.         encode_row(raw_rowbuf, cols, nPlanes);
  504.     }
  505.     if( table )
  506.         free(table);
  507.     free(raw_rowbuf);
  508. }
  509.  
  510.  
  511. static void
  512. ppm_to_24(fp, cols, rows, maxval)
  513.     FILE *fp;
  514.     int cols, rows, maxval;
  515. {
  516.     int formsize, nPlanes;
  517.     register int row, col;
  518.     pixel *pP;
  519.     pixval *table = NULL;
  520.     rawtype *redbuf, *greenbuf, *bluebuf;
  521.  
  522.     redbuf   = (rawtype *)xmalloc(cols * sizeof(rawtype));
  523.     greenbuf = (rawtype *)xmalloc(cols * sizeof(rawtype));
  524.     bluebuf  = (rawtype *)xmalloc(cols * sizeof(rawtype));
  525.  
  526.     nPlanes = 24;
  527.  
  528.     formsize =
  529.         4 +                                         /* ILBM */
  530.         4 + 4 + 20 +                                /* BMHD size header */
  531.         4 + 4 + rows * nPlanes * RowBytes(cols);    /* BODY size data */
  532.  
  533.     write_form_ilbm(formsize);
  534.     write_bmhd(cols, rows, nPlanes);
  535.  
  536.     /* write body */
  537.         put_fourchars("BODY");
  538.     put_big_long(rows * nPlanes * RowBytes(cols));
  539.  
  540.     if( maxval != MAXCOLVAL ) {
  541.         pm_message("maxval is not %d - automatically rescaling colors", MAXCOLVAL);
  542.         table = make_val_table(maxval, MAXCOLVAL);
  543.     }
  544.     for( row = 0; row < rows; row++ ) {
  545.         pP = next_pixrow(fp, row);
  546.         if( table ) {
  547.             for( col = 0; col < cols; col++, pP++ ) {
  548.                 redbuf[col]     = table[PPM_GETR(*pP)];
  549.                 greenbuf[col]   = table[PPM_GETG(*pP)];
  550.                 bluebuf[col]    = table[PPM_GETB(*pP)];
  551.             }
  552.         }
  553.         else {
  554.             for( col = 0; col < cols; col++, pP++ ) {
  555.                 redbuf[col]     = PPM_GETR(*pP);
  556.                 greenbuf[col]   = PPM_GETG(*pP);
  557.                 bluebuf[col]    = PPM_GETB(*pP);
  558.             }
  559.         }
  560.         encode_row(redbuf, cols, 8);
  561.         encode_row(greenbuf, cols, 8);
  562.         encode_row(bluebuf, cols, 8);
  563.     }
  564.     if( table )
  565.         free(table);
  566.     free(redbuf);
  567.     free(greenbuf);
  568.     free(bluebuf);
  569. }
  570.  
  571.  
  572. static void
  573. ppm_to_direct(fp, cols, rows, maxval, dcol)
  574.     FILE *fp;
  575.     int cols, rows, maxval;
  576.     DirectColor *dcol;
  577. {
  578.     int formsize, nPlanes;
  579.     register int row, col;
  580.     pixel *pP;
  581.     pixval *redtable = NULL, *greentable = NULL, *bluetable = NULL;
  582.     pixval redmaxval, greenmaxval, bluemaxval;
  583.     rawtype *redbuf, *greenbuf, *bluebuf;
  584.  
  585.     redbuf   = (rawtype *)xmalloc(cols * sizeof(rawtype));
  586.     greenbuf = (rawtype *)xmalloc(cols * sizeof(rawtype));
  587.     bluebuf  = (rawtype *)xmalloc(cols * sizeof(rawtype));
  588.  
  589.     nPlanes = dcol->r + dcol->g + dcol->b;
  590.     redmaxval   = pm_bitstomaxval(dcol->r);
  591.     if( redmaxval != maxval ) {
  592.         pm_message("rescaling reds to %d bits", dcol->r);
  593.         redtable = make_val_table(maxval, redmaxval);
  594.     }
  595.     greenmaxval = pm_bitstomaxval(dcol->g);
  596.     if( greenmaxval != maxval ) {
  597.         pm_message("rescaling greens to %d bits", dcol->g);
  598.         greentable = make_val_table(maxval, greenmaxval);
  599.     }
  600.     bluemaxval  = pm_bitstomaxval(dcol->b);
  601.     if( bluemaxval != maxval ) {
  602.         pm_message("rescaling blues to %d bits", dcol->b);
  603.         bluetable = make_val_table(maxval, bluemaxval);
  604.     }
  605.  
  606.     formsize =
  607.         4 +                                         /* ILBM */
  608.         4 + 4 + 20 +                                /* BMHD size header */
  609.         4 + 4 + 4 +                                 /* DCOL size description */
  610.         4 + 4 + rows * nPlanes * RowBytes(cols);    /* BODY size data */
  611.  
  612.     write_form_ilbm(formsize);
  613.     write_bmhd(cols, rows, nPlanes);
  614.  
  615.     /* write DCOL */
  616.     put_fourchars("DCOL");
  617.     put_big_long(4);
  618.     put_byte(dcol->r);
  619.     put_byte(dcol->g);
  620.     put_byte(dcol->b);
  621.     put_byte(0);    /* pad */
  622.  
  623.     /* write body */
  624.     put_fourchars("BODY");
  625.     put_big_long(rows * nPlanes * RowBytes(cols));
  626.  
  627.     for( row = 0; row < rows; row++ ) {
  628.         pP = next_pixrow(fp, row);
  629.         for( col = 0; col < cols; col++, pP++ ) {
  630.             register pixval r, g, b;
  631.  
  632.             r = PPM_GETR(*pP); if( redtable ) r = redtable[r];
  633.             g = PPM_GETG(*pP); if( greentable ) g = greentable[g];
  634.             b = PPM_GETB(*pP); if( bluetable ) b = bluetable[b];
  635.  
  636.             redbuf[col] = r;
  637.             greenbuf[col] = g;
  638.             bluebuf[col] = b;
  639.         }
  640.         encode_row(redbuf, cols, dcol->r);
  641.         encode_row(greenbuf, cols, dcol->g);
  642.         encode_row(bluebuf, cols, dcol->b);
  643.     }
  644.     if( redtable )
  645.         free(redtable);
  646.     if( greentable )
  647.         free(greentable);
  648.     if( bluetable )
  649.         free(bluetable);
  650.     free(redbuf);
  651.     free(greenbuf);
  652.     free(bluebuf);
  653. }
  654.  
  655.  
  656. static void
  657. ppm_to_cmap(maxval, chv, colors)
  658.     int maxval;
  659.     colorhist_vector chv;
  660.     int colors;
  661. {
  662.     int formsize, cmapsize;
  663.  
  664.     cmapsize = colors * 3;
  665.     if( odd(cmapsize) )
  666.         cmapsize++;     /* pad to a word */
  667.  
  668.     formsize =
  669.         4 +                                         /* ILBM */
  670.         4 + 4 + 20 +                                /* BMHD size header */
  671.         4 + 4 + cmapsize;                           /* CMAP size colormap */
  672.  
  673.     write_form_ilbm(formsize);
  674.     write_bmhd(0, 0, 0);
  675.     write_std_cmap(chv, colors, maxval);
  676. }
  677.  
  678.  
  679. static void
  680. ppm_to_std(fp, cols, rows, maxval, chv, colors, nPlanes)
  681.     FILE *fp;
  682.     int cols, rows, maxval;
  683.     colorhist_vector chv;
  684.     int colors, nPlanes;
  685. {
  686.     int formsize, cmapsize;
  687.     colorhash_table cht;
  688.     register int row, col;
  689.     pixel *pP;
  690.     rawtype *raw_rowbuf;
  691.  
  692.     raw_rowbuf = (rawtype *)xmalloc(cols * sizeof(rawtype));
  693.  
  694.     /* Make a hash table for fast color lookup. */
  695.     cht = ppm_colorhisttocolorhash(chv, colors);
  696.  
  697.     cmapsize = colors * 3;
  698.     if( odd(cmapsize) )
  699.         cmapsize++;     /* pad CMAP to a word */
  700.  
  701.     formsize =
  702.         4 +                                         /* ILBM */
  703.         4 + 4 + 20 +                                /* BMHD size header */
  704.         4 + 4 + cmapsize +                          /* CMAP size colormap */
  705.         4 + 4 + rows * nPlanes * RowBytes(cols);    /* BODY size data */
  706.  
  707.     write_form_ilbm(formsize);
  708.     write_bmhd(cols, rows, nPlanes);
  709.     write_std_cmap(chv, colors, maxval);
  710.  
  711.     /* write body */
  712.     put_fourchars("BODY");
  713.     put_big_long(rows * nPlanes * RowBytes(cols));
  714.  
  715.     for( row = 0; row < rows; row++ ) {
  716.         for( col = 0, pP = next_pixrow(fp, row); col < cols; col++, pP++ ) {
  717.             int ind;
  718.  
  719.             /* Check hash table to see if we have already matched this color. */
  720.             ind = ppm_lookupcolor(cht, pP);
  721.             if( ind == -1 ) {
  722.                 /* No; search colormap for closest match. */
  723.                 /* algorithm taken from ppmquant.c   -IUW */
  724.                 register int i, r1, g1, b1, r2, g2, b2;
  725.                 register long dist, newdist;
  726.  
  727.                 r1 = PPM_GETR(*pP);
  728.                 g1 = PPM_GETG(*pP);
  729.                 b1 = PPM_GETB(*pP);
  730.                 dist = 2000000000;
  731.                 for( i = 0; i < colors; ++i ) {
  732.                     r2 = PPM_GETR(chv[i].color);
  733.                     g2 = PPM_GETG(chv[i].color);
  734.                     b2 = PPM_GETB(chv[i].color);
  735.                     newdist = ( r1 - r2 ) * ( r1 - r2 ) +
  736.                               ( g1 - g2 ) * ( g1 - g2 ) +
  737.                               ( b1 - b2 ) * ( b1 - b2 );
  738.                     if( newdist < dist ) {
  739.                         ind = i;
  740.                         dist = newdist;
  741.                     }
  742.                 }
  743.             }
  744.             raw_rowbuf[col] = ind;
  745.         }
  746.         encode_row(raw_rowbuf, cols, nPlanes);
  747.     }
  748. }
  749.  
  750.  
  751. static void
  752. write_std_cmap(chv, colors, maxval)
  753.     colorhist_vector chv;
  754.     int colors, maxval;
  755. {
  756.     int cmapsize, i;
  757.  
  758.     cmapsize = 3 * colors;
  759.  
  760.     /* write colormap */
  761.     put_fourchars("CMAP");
  762.     put_big_long(cmapsize);
  763.     if( maxval != MAXCOLVAL ) {
  764.         pixval *table;
  765.         pm_message("maxval is not %d - automatically rescaling colors", MAXCOLVAL);
  766.         table = make_val_table(maxval, MAXCOLVAL);
  767.         for( i = 0; i < colors; i++ ) {
  768.             put_byte((char)(table[PPM_GETR(chv[i].color)]));
  769.             put_byte((char)(table[PPM_GETG(chv[i].color)]));
  770.             put_byte((char)(table[PPM_GETB(chv[i].color)]));
  771.         }
  772.         free(table);
  773.     }
  774.     else {
  775.         for( i = 0; i < colors; i++ ) {
  776.             put_byte(PPM_GETR(chv[i].color));
  777.             put_byte(PPM_GETG(chv[i].color));
  778.             put_byte(PPM_GETB(chv[i].color));
  779.         }
  780.     }
  781.     if( odd(cmapsize) )
  782.         put_byte(0);
  783. }
  784.  
  785.  
  786. static void
  787. write_form_ilbm(size)
  788.     int size;
  789. {
  790.     put_fourchars("FORM");
  791.     put_big_long(size);
  792.     put_fourchars("ILBM");
  793. }
  794.  
  795.  
  796. static void
  797. write_bmhd(cols, rows, nPlanes)
  798.     int cols, rows, nPlanes;
  799. {
  800.     put_fourchars("BMHD");
  801.     put_big_long(20);
  802.  
  803.     put_big_short(cols);
  804.     put_big_short(rows);
  805.     put_big_short(0);       /* x */
  806.     put_big_short(0);       /* y */
  807.     put_byte(nPlanes);
  808.     put_byte(mskNone);      /* masking type */
  809.     put_byte(cmpNone);      /* compression type */
  810.     put_byte(0);            /* pad1 */
  811.     put_big_short(0);       /* tranparentColor */
  812.     put_byte(10);           /* xAsp */
  813.     put_byte(10);           /* yAsp */
  814.     put_big_short(cols);    /* pageWidth */
  815.     put_big_short(rows);    /* pageHeight */
  816. }
  817.  
  818.  
  819. /* encode algorithm by Johan Widen (jw@jwdata.se) */
  820. const unsigned char bit_mask[] = {1, 2, 4, 8, 16, 32, 64, 128};
  821.  
  822. static void
  823. encode_row(row, cols, nPlanes)
  824.     rawtype *row;
  825.     int cols, nPlanes;
  826. {
  827.     register int plane, col;
  828.     int bytes;
  829.  
  830.     bytes = RowBytes(cols);
  831.  
  832.     /* Encode and write raw bytes in plane-interleaved form. */
  833.     for( plane = 0; plane < nPlanes; plane++ ) {
  834.         int mask, cbit, wr;
  835.         unsigned char *cp;
  836.         rawtype *rp;
  837.  
  838.         mask = 1 << plane;
  839.         cbit = -1;
  840.         cp = coded_rowbuf-1;
  841.         rp = row;
  842.         for( col = 0; col < cols; col++, cbit--, rp++ ) {
  843.             if( cbit < 0 ) {
  844.                 cbit = 7;
  845.                 *++cp = 0;
  846.             }
  847.             if( *rp & mask )
  848.                 *cp |= bit_mask[cbit];
  849.         }
  850.         wr = fwrite(coded_rowbuf, 1, bytes, stdout);
  851.         if( wr != bytes )
  852.             pm_error("write error");
  853.     }
  854. }
  855.  
  856.  
  857. static int
  858. colorstobpp(colors)
  859.     int colors;
  860. {
  861.     int i;
  862.  
  863.     for( i = 1; i <= MAXPLANES; i++ ) {
  864.         if( colors <= (1 << i) )
  865.             return i;
  866.     }
  867.     pm_error("too many planes (max %d)", MAXPLANES);
  868. }
  869.  
  870.  
  871. #if 0
  872. static void
  873. put_fourchars(str)
  874.     char* str;
  875. {
  876.     fputs( str, stdout );
  877. }
  878. #endif
  879.  
  880.  
  881. static void
  882. put_big_short(s)
  883.     short s;
  884. {
  885.     if ( pm_writebigshort( stdout, s ) == -1 )
  886.         pm_error( "write error" );
  887. }
  888.  
  889.  
  890. static void
  891. put_big_long(l)
  892.     long l;
  893. {
  894.     if ( pm_writebiglong( stdout, l ) == -1 )
  895.         pm_error( "write error" );
  896. }
  897.  
  898.  
  899. #if 0
  900. static void
  901. put_byte(b)
  902.     unsigned char b;
  903. {
  904.     (void) putc( b, stdout );
  905. }
  906. #endif
  907.  
  908.  
  909. static int
  910. get_int_val(string, option, bot, top)
  911.     char *string, *option;
  912.     int bot, top;
  913. {
  914.     int val;
  915.  
  916.     if( sscanf(string, "%d", &val) != 1 )
  917.         pm_error("option \"%s\" needs integer argument", option);
  918.  
  919.     if( val < bot || val > top )
  920.         pm_error("option \"%s\" argument value out of range (%d..%d)", option, bot, top);
  921.  
  922.     return val;
  923. }
  924.  
  925.  
  926.  
  927.  
  928. static pixval *
  929. make_val_table(oldmaxval, newmaxval)
  930.     pixval oldmaxval, newmaxval;
  931. {
  932.     int i;
  933.     pixval *table;
  934.  
  935.     table = xmalloc((oldmaxval + 1) * sizeof(pixval));
  936.     for(i = 0; i <= oldmaxval; i++ )
  937.         table[i] = (i * newmaxval + oldmaxval/2) / oldmaxval;
  938.  
  939.     return table;
  940. }
  941.  
  942.  
  943. static void *
  944. xmalloc(bytes)
  945.     int bytes;
  946. {
  947.     void *mem;
  948.  
  949.     mem = malloc(bytes);
  950.     if( mem == NULL )
  951.         pm_error("out of memory allocating %d bytes", bytes);
  952.     return mem;
  953. }
  954.  
  955.  
  956. static int  gFormat;
  957. static int  gCols;
  958. static int  gMaxval;
  959.  
  960. static void
  961. init_read(fp, colsP, rowsP, maxvalP, readall)
  962.     FILE *fp;
  963.     int *colsP, *rowsP;
  964.     pixval *maxvalP;
  965.     int readall;
  966. {
  967.     if( readall ) {
  968.         pixels = ppm_readppm(fp, colsP, rowsP, maxvalP);
  969.     }
  970.     else {
  971.         ppm_readppminit(fp, colsP, rowsP, maxvalP, &gFormat);
  972.         pixrow = ppm_allocrow(*colsP);
  973.     }
  974.     gCols = *colsP;
  975.     gMaxval = *maxvalP;
  976. }
  977.  
  978.  
  979. static pixel *
  980. next_pixrow(fp, row)
  981.     FILE *fp;
  982.     int row;
  983. {
  984.     if( pixels )
  985.         pixrow = pixels[row];
  986.     else {
  987.         static int rowcnt;
  988.         if( row != rowcnt )
  989.             pm_error("big mistake");
  990.         rowcnt++;
  991.         ppm_readppmrow(fp, pixrow, gCols, gMaxval, gFormat);
  992.     }
  993.     return pixrow;
  994. }
  995.  
  996.